﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading;
using LINQPad;
using LINQPad.Extensibility.DataContext;
using Microsoft.CSharp;
using Microsoft.Web.Administration;

namespace LINQPadLogParser
{
  public class LogParser : DynamicDataContextDriver
  {
    public override string Name
    {
      get { return "LogParser"; }
    }

    public override string Author
    {
      get { return "Alexander Ovchinnikov"; }
    }

    public override string GetConnectionDescription(IConnectionInfo cxInfo)
    {
      return cxInfo.DisplayName;
    }

    public override bool ShowConnectionDialog(IConnectionInfo cxInfo, bool isNewConnection)
    {
      cxInfo.DisplayName = "IIS Logs";
      return true;
    }

    public override List<ExplorerItem> GetSchemaAndBuildAssembly(IConnectionInfo cxInfo, AssemblyName assemblyToBuild, ref string nameSpace, ref string typeName)
    {
      var manager = new ServerManager();
      List<ExplorerItem> list =
        manager.Sites.OrderBy(a => a.Name)
          .Select(a => new ExplorerItem(a.Id + " - " + a.Name, ExplorerItemKind.QueryableObject, ExplorerIcon.Table) {DragText = "Site(" + a.Id + ")"})
          .ToList();

      CompilerResults results;
      using (var codeProvider = new CSharpCodeProvider(new Dictionary<string, string> {{"CompilerVersion", "v4.0"}}))
      {
        var options = new CompilerParameters(new string[0], assemblyToBuild.CodeBase, true);
        var codes = new List<string> {"class EmptyClass { }"};
        results = codeProvider.CompileAssemblyFromSource(options, codes.ToArray());
      }

      if (results.Errors.Count > 0)
        throw new Exception("Cannot compile typed context: " + results.Errors[0].ErrorText + " (line " + results.Errors[0].Line + ")");
      nameSpace = "LINQPadLogParser";
      typeName = "LogParserDataContext";

      return list;
    }

    public override void PreprocessObjectToWrite(ref object objectToWrite, ObjectGraphInfo info)
    {
      objectToWrite = Preprocess(objectToWrite);
    }

    private static object Preprocess(object objectToWrite)
    {
      if (objectToWrite != null &&
          (objectToWrite is IPAddress || objectToWrite is IPEndPoint || objectToWrite is SimpleUriWrapper || objectToWrite is UriWrapper ||
           objectToWrite is IPAddressWrapper || objectToWrite is Int32Wrapper || objectToWrite is Uri || objectToWrite is DateTimeWrapper ||
           objectToWrite is IPEndPointWrapper || objectToWrite is TimeSpanMillisecondsWrapper))
      {
        return new DumpContainer(objectToWrite.ToString());
      }
      return objectToWrite;
    }

    public override void OnQueryFinishing(IConnectionInfo cxInfo, object context, QueryExecutionManager executionManager)
    {
      base.OnQueryFinishing(cxInfo, context, executionManager);
#if SpeedTest
      ("Time: " + (Process.GetCurrentProcess().TotalProcessorTime - _time) + " Reads: " + Reads + " Key time: " +
       Ticks*1000/Stopwatch.Frequency + "ms").Dump();
#endif
      //LogParserDataContext.LineManager = null;
    }

    public override void InitializeContext(IConnectionInfo cxInfo, object context, QueryExecutionManager executionManager)
    {
      base.InitializeContext(cxInfo, context, executionManager);
      Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
#if SpeedTest
      Reads = 0;
      _time = Process.GetCurrentProcess().TotalProcessorTime;
#endif
    }
  }

#if SpeedTest
  public partial class LogParser
  {
    public static int Reads;
    public static long Ticks;
    private TimeSpan _time;
  }
#endif
}